package com.baishui.context.support;


import com.baishui.aop.aspectj.AspectJAutoProxyCreator;
import com.baishui.beans.factory.NoSuchBeanDefinitionException;
import com.baishui.beans.factory.annotation.AutowiredAnnotationProcessor;
import com.baishui.beans.factory.config.ConfigurableBeanFactory;
import com.baishui.beans.factory.support.DefaultBeanFactory;
import com.baishui.beans.factory.xml.XmlBeanDefinitionReader;
import com.baishui.context.ApplicationContext;
import com.baishui.core.Resource;
import com.baishui.utils.ClassUtils;

import java.util.List;

/**
 * 抽象工厂
 * 将公共的部分抽取出来
 */
public abstract class AbstractApplicationContext implements ApplicationContext {

	private DefaultBeanFactory factory = null;

	private ClassLoader classLoader;

	public AbstractApplicationContext(String configFile){
		factory = new DefaultBeanFactory();
		/**
		 * 注册beanFactory -> BeanDefinitionRegistry
		 */
		XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
		/**
		 * 获取不同的Resource
		 */
		Resource resource = this.getResourceByPath(configFile);
		/**
		 * 重要：解析classpath或者file或者包路径的class -> BeanDefiniton
		 */
		reader.loadBeanDefinitions(resource);

		factory.setBeanClassLoader(this.getBeanClassLoader());
		/**
		 * 注册beanPostProcessors
		 */
		registerBeanPostProcessors(factory);
		/**
		 * 至此为止，BeanFactory中存在了很多预装的实例对象 @README中
		 */
	}

	/**
	 * @see DefaultBeanFactory#getBean(String) 
	 * @param beanID
	 * @return
	 */
	public Object getBean(String beanID) {
		return factory.getBean(beanID);
	}

	/**
	 * V2-2-2:模板方法
	 * Resource 的创建由子类进行实现
	 * @param path
	 * @return
	 */
	protected abstract Resource getResourceByPath(String path);

	public ClassLoader getBeanClassLoader() {
		return this.classLoader;
	}

	public void setBeanClassLoader(ClassLoader beanClassLoader) {
		this.classLoader = beanClassLoader==null ? ClassUtils.getDefaultClassLoader():beanClassLoader;
	}

	protected void registerBeanPostProcessors(ConfigurableBeanFactory beanFactory) {
		/**
		 * autowire
		 */
		{
			AutowiredAnnotationProcessor postProcessor = new AutowiredAnnotationProcessor();
			postProcessor.setBeanFactory(beanFactory);
			beanFactory.addBeanPostProcessor(postProcessor);
		}

		/**
		 * AOP
		 */
		{
			AspectJAutoProxyCreator postProcessor = new AspectJAutoProxyCreator();
			postProcessor.setBeanFactory(beanFactory);
			beanFactory.addBeanPostProcessor(postProcessor);
		}

	}

	public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
		return this.factory.getType(name);
	}

	public List<Object> getBeansByType(Class<?> type){
		return this.factory.getBeansByType(type);
	}

}
